home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Disc to the Future 2
/
Disc to the Future Part II Programmer's Reference (Wayzata Technology)(6013)(1992).bin
/
MAC
/
THINKC
/
3_0
/
RAMSTART
/
RS(MAIN).C
< prev
Wrap
Text File
|
1988-01-17
|
28KB
|
922 lines
/*
RS(Main).c RamStart
By: George A. Nelson on 1 February 1985
19 March 1985 ver 1
15 May 1985 ver 1.1
10 July 1985 ver 1.11
24 July 1985 ver 1.2
2 August 1985 ver 1.21
23 August 1985 ver 1.22
4 May 1986 ver 1.23
25 May 1986 ver 1.24
20 August 1986 ver 1.3
17 October 1986 ver 1.31
4 February 1987 ver 1.32
28 March 1987 ver 1.4
11 January 1988 ver 1.41
Description: Excellent RAM disk derived from Apple's sample, (c) Apple
Computer 1983, written Dec '83 by MDB (?). This version is re-sizable
and re-inserts itself when ejected. RamStart copies all files in its
own folder or named in a text file to the new RAM disk, and, if a
System and a Finder (or the application named in the text file) were
copied, ejects its disk and starts the Finder on the RAM disk.
While I try to follow the user interface guidelines, this is not an
event-driven program. When it is copying files, it can be a bit slow
to respond to the user's pressing a control.
When invoked for the first time in a session (usually as the startup
program), RamStart reserves space for the RAM disk. The memory is
actually only reserved by the Segment Loader when the application heap
zone is initialized, so RamStart launches itself to cause this. It is
during the second run that the RAM disk is created and files are copied
to it. RamStart then starts the Finder on the RAM disk (if a System
and a Finder were copied).
If RamStart finds that there is already a RAM disk in memory (on third
and subsequent runs), it give the user the choice of what to do.
This program must overcome a major communications problem. Variables
known to one section of code are unavailable to others, since they
occur in different runs! From the first run of the program, when
memory is reserved, to the second, when the RAM disk driver is opened
to create the RAM disk, the location of the RAM disk is remembered in a
low memory global, ApplScratch. This seems to cause Microsoft programs
to forget that they have seen the original master disk. Too bad. When
the program is run again, by accident or to change or remove the RAM
disk, this value may no longer be good -- another application may have
used ApplScratch. The driver refNum is reconstructed from the DRVR
resource, whose name we know. If the RAM disk driver is present, it
responds to a Status call with a record containing its signature (so we
can be sure that our driver responded, and not, say, the Assimilation
Process RAM disk), and a handle containing a pointer to the RAM disk,
the old value of BufPtr (we set BufPtr to point to the RAM disk to
reserve its memory), and a pointer to the drive queue entry.
RamStart determines which run it is in when it starts up. First it
tries to get the driver's status; if it can, it is in "phase 3".
Otherwise, it checks ApplScratch for the signature; if it finds one it
is in "phase 2". Otherwise it is in "phase 1".
Apple (Harvey Alcabes) suggests that driver (and desk accessory)
numbers should be assigned "on the fly". When installing a driver in a
System file, this means to use an unused resource id. My driver, by
not being installed in any System file, illustrates the problems with
Apple's "solution", which is that the startup disk can change with each
application launch, while drivers typically remain open. Who can tell
what conflict will arise with another System file? Instead, RamStart
is shipped with the driver ID set to be the same as Assimilation's, 11,
so all RAM disk users will experience the same conflicts.
Related files:
RS(Copy).c
RS(Dlog).c
RS.h
RamDisk.asm
RamStart.r
RamIcon
//
Bugs:
13 March 85. Driver #10 is also the AppleBus. What driver number
would be safer? (17 April 85. Apple has only a scummy kludge to
offer: pick an unused number at open time and hope that it doesn't
conflict with a driver in any subsequent active System file.)
14 March 85. The System file can't be copied from the RAM disk. I set
the Protected bit to cause this, 'cause copying it to a real disk
makes the real disk unbootable. The boot blocks on the RAM disk are
not inited, and the Finder copies them too when it copies the System.
2 April 85. Fixed. NoRamDisk() was causing the screen to be trashed by
changing BufPtr before the RAM disk went away. This points up the
communications problems in the program.
17 May 85. Fixed. The new multiple-opens CopyFolder() would not copy
more files than fit in one pass. A comment claimed that the last file
opened was closed to ensure that a destination file would be opened;
this was not done and wouldn't have worked anyway (how to copy the last
file?). A new subroutine checks whether a file can be opened; if not,
it finds a file to close, which will be copied next time. Poor testing.
10 July 85. Fixed. Bundle bit now set. Shows proper version data, and
contains proper version data in resource file. Slight changes to help
file.
17 July 85. U Alberta asked for a version that would make it hard to copy
files from the RAM disk. Compile-time switch sets protected bit on all
files.
Why did I think that my "protect" code worked? The new code, copied
from Examine File, does.
2 Aug 85. Changed rules for getting RamStart to keep the ducks at bay.
23 Aug 85. Fixed RTE in driver. I hadn't understood why the original
RAM disk driver did this; neither had the author. It was for asynch
routines that had disabled vertical retrace interrupts. It doesn't
work on the 68010. Reported by Levco.
21 March 86. Version for HFS, at Consulair's request. This should be
the last free version, barring other bug fixes.
2 May 86. Still HFS version. Removed Protect() code; it fails under HFS.
Put INIT's and data fork back in System file. Sat to make it bigger,
but it's the only safe thing to do.
21 May 86. Crashes if trying to remove an old-version RAM disk on a Mac+./
25 May 86, 1.24. Re-inserts based on actual drive number, rather than
hardwired "drive 3".
HFS 3.1.1 and 1.1a3 do not pass "eject" for non-ejectable volumes -- and
don't return an error code and still allow the volume to be unmounted!
Apple's bug prevents RAM disk from re-inserting.
20 August 86, 1.3. Converted to LightspeedC. Now sets size of drive in
drive queue element (still can't format from Finder with DI pack).
Fixed bug in copying many files -- would leave out the last one of a
batch -- using a simpler method for finding the number of files that
can be opened. Now says "opening..." as well as "copying..." -- HFS
can be _very_ slow opening files (use MFS instead). Improved error
reporting: can now print a string, such as a file name.
17 October 86, 1.31. Steve Hanna reported bug, miscalled _HandToHand
(the interface had changed from Consulair). This caused a crash when
a ".ram" file was changed to a RamStart Script document.
4 February 87, 1.32. Now hides more types of "system" file, notably
printer drivers. Converted to LightSpeedC ver 2.01, using its HFS
definitions. New item in Already dialog to tell user why the RAM
disk can't be removed. Version intended for distribution by Apple.
28 March 87, 1.4. Added "many little files" box, which triples the
size of the RAM disk directory. Unchecked, there is 1 dir block for
every 40K of disk space, or enough for 6K byte average files. Checked
there are 3 dir blocks for every 40K of disk space, or enough for 2K
byte average files. The option is useful for a RAM disk of header
files.
10 January 88, 1.41. Faster clear of RAM disk storage when opened.
Changed my address. Minor changes to documentation. Declaration of
controlParam structure of RamStatusPB placed in line; Think has
screwed up the definition in DeviceMgr.h. Now close last file being
copied to the RAM disk in CloseFiles() (when copying is aborted);
Apple changed UnmountVol for Multifinder and it no longer closes files
but gives an error instead. Added yet more types to "hide me" list
in CopyFile().
*/
/* // */
#include <MacTypes.h>
#include <DialogMgr.h>
#include <MemoryMgr.h>
#include <ResourceMgr.h>
#include <FileMgr.h>
#include <DeviceMgr.h>
#include <ToolboxUtil.h>
#include <SegmentLdr.h>
#include <SetJmp.h>
#include "RS.h"
/* Defined here */
typedef struct { /* Info similar to RamInfo, passed from phase 0 */
long signature; /* to phase 1. */
char *oldBufPtr;
short initCmd; /* 'BD' requests big dir from the driver open */
short initVal; /* size factor for big directory */
} ApplInfo;
#define applInfo (*(ApplInfo *)&ApplScratch)
typedef struct {
struct {
QElemPtr qLink;
int qType;
int ioTrap;
Ptr ioCmdAddr;
ProcPtr ioCompletion;
OsErr ioResult;
StringPtr ioNamePtr;
int ioVRefNum;
int ioRefNum;
int csCode;
int csParam[];
} pb;
RamStatus stat;
} RamStatusPB;
RamInfo ramInfo; /* For NoRamDisk() and MakeCtlW(). */
short ramID; /* " */
char copyRight[] = "\pā1985-1988 George A. Nelson; portions ā1983 Apple Computer.";
jmp_buf env; /* for TestDlog() */
short MakeRamDisk();
short UnusedDrive();
short DoAlready();
char CopyFolder();
/* // */
main()
{
short mssg;
if( Button() && TraceTrap < ROMBase ) /* break to the debugger, if one is present */
Debugger();
InitGraf( &thePort );
InitFonts();
InitWindows();
TEInit(); /* required for dialogs */
InitMenus(); /* required for dialogs? */
InitDialogs( NULL );
SetCursor( *GetCursor(watchCursor) );
/* Catch a signal from TestDLOG and call GetNewSize(). This allows
other routines to clean up first. */
if( (mssg = setjmp(env)) ) {
if( mssg == 'SZ' )
GetNewSize();
else error( "\pUnknown setjmp() message ^2", (long)mssg );
}
/* set ramID to the RAM disk driver refNum from the driver resource */
{
Handle dh;
long rType;
Str255 rName;
SetResLoad( FALSE );
dh = GetNamedResource('DRVR', RamName );
SetResLoad( TRUE );
GetResInfo( dh, &ramID, &rType, &rName ); /* ramID is global. */
}
/* // */
/* Ask the driver if we are in phase 3. If not, check ApplScratch to
see if we are in phase 2. Otherwise, we are in phase 1 ('cause nothing
was set up yet). */
{
RamStatusPB ramStatusPB;
short actualRamID;
Boolean diskExists = FALSE;
Clear( ramStatusPB );
ramStatusPB.pb.ioRefNum = ~(actualRamID = ramID);
if( PBStatus(&ramStatusPB, FALSE) == noErr && ramStatusPB.stat.signature == RamSignature )
diskExists = TRUE;
else {
Clear( ramStatusPB );
ramStatusPB.pb.ioRefNum = ~10; /* Driver refNum we used to use. */
if( PBStatus(&ramStatusPB, FALSE) == noErr && ramStatusPB.stat.signature == RamSignature ) {
diskExists = TRUE;
actualRamID = 10;
}
}
if( diskExists )
{
DoPhase3( &ramStatusPB, actualRamID );
}
else if( applInfo.signature == RamSignature )
DoPhase2();
else DoPhase1();
}
}
/* // */
/* The phases follow. Each phase is a different run of the program.
Variables cannot be passed from one phase to another! Instead, low memory
locations or handles to data in the system heap are used. */
/* In phase 1. No RAM disk is installed. Reserve memory for a RAM disk
and run again to get that memory reserved. */
#define round 40
#define hrTop 50
#define hrLeft 140
#define hrBottom 132
#define hrRight 372
#define irTop ((hrTop+hrBottom-32)/2)
#define irLeft (hrLeft+30)
#define irBottom (irTop+32)
#define irRight (irLeft+32)
DoPhase1()
{
long heapSize, dirSize;
Ptr ramStart;
short i, lMargin;
char *version, **versionH, *ctrlFileName;
static Rect helloR = { hrTop, hrLeft, hrBottom, hrRight },
iconR = { irTop, irLeft, irBottom, irRight };
/* say hello */
versionH = GetResource( 'GANr', 0 );
DetachResource( versionH );
HLock( versionH );
version = *versionH;
for( i = 1; i < version[0]; ++i ) { /* keep only version data */
if( version[i] == ',' )
version[0] = i - 1;
}
lMargin = ( irRight + hrRight - StringWidth(version) - 5 )/2;
PenNormal();
PenSize( 5, 5 );
FillRoundRect( &helloR, round, round, &white );
FrameRoundRect( &helloR, round, round );
PlotIcon( &iconR, GetResource('ICN#', 128) );
MoveTo( lMargin, (hrTop + hrBottom)/2 - 10 );
DrawString( version );
MoveTo( lMargin, (hrTop + hrBottom)/2 + 6);
DrawString( "\pHFS compatible" );
/* // */
/* reserve the RAM disk memory */
GetCtrlFile( &ctrlFileName );
heapSize = *(long *)*GetResource( 'RAMD', 256 );
dirSize = *(long *)*GetResource( 'RAMD', 257 );
ramStart = (Ptr)GetZone() + heapSize;
InitRamDisk( heapSize, ramStart, dirSize ); /* May not return. */
ReStartUs(); /* Never returns. */
}
/* // */
/* In phase 2. By now, there is space for the RAM disk. */
DoPhase2()
{
long size;
short ramDrvNum, ramRefNum, go;
RamStatusPB ramStatusPB;
char *ctrlFileName, *exitAppl;
DialogPtr threat;
ramInfo.ramDisk = BufPtr;
ramInfo.oldBufPtr = applInfo.oldBufPtr;
size = ramInfo.oldBufPtr - ramInfo.ramDisk; /* Size of RAM disk. */
applInfo.signature = 0; /* don't do phase 2 again */
if( size < MinDisk ) {
error("\pRAM disk not properly inited, old BufPtr=^2, BufPtr=^3", ramInfo.oldBufPtr, BufPtr);
size = MinDisk;
}
threat = GetNewDialog( dlogThreat, NULL, -1 ); /* "Free" means don't sell RamStart! */
BeginUpdate( threat ); /* Normally done via Update event. */
DrawDialog( threat );
EndUpdate( threat );
GetCtrlFile( &ctrlFileName );
MakeCtlW( size );
ramRefNum = MakeRamDisk();
ramDrvNum = UnusedDrive();
ChgDrvQ( ramRefNum, ramDrvNum, size ); /* Even if the new drive claims not to be write */
FixVolInfo( ramDrvNum ); /* protected, this must be done. */
ZapControlFile( ramDrvNum );
/* Save ramInfo for next phase. Use driver's data handle. */
Clear( ramStatusPB );
ramStatusPB.pb.ioRefNum = ~ramID;
if( PBStatus(&ramStatusPB, FALSE) == noErr && ramStatusPB.stat.signature == RamSignature ) {
SetHandleSize( ramStatusPB.stat.ramInfoh, sizeof(RamInfo) );
(*ramStatusPB.stat.ramInfoh)->oldBufPtr = ramInfo.oldBufPtr;
(*ramStatusPB.stat.ramInfoh)->drvQEntry = ramInfo.drvQEntry;
}
else {
error("\pcan't get RAM disk driver status, ioResult=^2", (long)ramStatusPB.pb.ioResult);
ExitToShell();
}
/* Copy the files to the RAM disk. */
exitAppl = FinderName; /* default, may be changed if there is a control file */
if( ctrlFileName )
go = CopyCtrlFile( ctrlFileName, ramDrvNum, &exitAppl );
else
go = CopyFolder( ramDrvNum, CurApName, FinderName );
if( go == (HadSystem + HadFinder) ) /* TRUE if had a System and a Finder. */
LaunchRamDisk( ramDrvNum, exitAppl );
}
/* // */
/* In phase 3. A RAM disk is already installed. Set the info needed by
NoRamDisk(). Ask the user what to do: leave the RAM disk alone, remove
it, or replace it with a new one. */
DoPhase3( ramStatusPBp, actualRamID )
RamStatusPB *ramStatusPBp;
short actualRamID;
{
long size, itemHit, heapSize, dirSize;
Ptr ramStart;
char *ctrlFileName;
short oldRamID;
ramInfo = **ramStatusPBp->stat.ramInfoh;
size = ramInfo.oldBufPtr - ramInfo.ramDisk; /* Size of RAM disk. */
itemHit = DoAlready( (long)ramInfo.drvQEntry & ~1L ); /* Ask the user. */
if( itemHit != alreadyIQuit ) {
oldRamID = ramID; /* Either New or Remove. */
ramID = actualRamID; /* This foolishness handles ID=10 RAM disks. */
NoRamDisk();
ramID = oldRamID;
if( itemHit == alreadyINew ) {
GetCtrlFile( &ctrlFileName );
heapSize = *(long *)*GetResource( 'RAMD', 256 );
dirSize = *(long *)*GetResource( 'RAMD', 257 );
ramStart = (Ptr)GetZone() + heapSize;
InitRamDisk( heapSize, ramStart, dirSize );
ReStartUs(); /* Never returns. */
}
}
ExitToShell();
}
/* // */
/* Check the application parameters for a control file: a text file with
our creator or a name ending in ".ram" (capitalization unimportant). If
such a file is found, we will use it to set up the RAM disk.
Since the context of this run is the control file, the current volume is
set to the control file's volume. Open the control file's resource fork;
if one is not present, create it. If the file's creator is not us, set it
to us. If the RAMD resource is not present in the file, copy it to the
file. Save the index of the file for deleting it from the appl parms list;
the rest of them will be available to the application we will launch. */
typedef struct {
short message;
short count;
char fList; /* an array of variable length structures */
} ApplParms;
typedef struct {
short vRefNum;
long type;
short filler;
char fName[2]; /* actually length of name, plus filler to even length */
} FEntry;
long fEntryIndex;
short fEntryLength;
GetCtrlFile( nameP )
char **nameP;
{
ApplParms *applParmP;
FEntry *fEntry;
short i, j, k;
ioParam pb;
fileParam fpb;
char suffix[MAXLINE];
short resRefNum;
Handle ramH;
*nameP = NULL; /* assume no control file */
if( AppParmHandle ) {
HLock( AppParmHandle );
applParmP = *(ApplParms **)AppParmHandle;
for( fEntry = (FEntry *)&applParmP->fList, i = 1;
i <= applParmP->count;
fEntry = (FEntry *)( (char *)fEntry + ((sizeof(FEntry) + fEntry->fName[0]) & ~0x1) ), ++i )
{
if( fEntry->type == 'TEXT' ) {
Clear( fpb );
fpb.ioNamePtr = (StringPtr)fEntry->fName;
fpb.ioVRefNum = fEntry->vRefNum;
PBGetFInfo( &fpb, FALSE );
/* find extension (.xxx) */
for( j = fEntry->fName[0]; j && fEntry->fName[j] != '.'; --j )
;
suffix[0] = fEntry->fName[0] - j + 1;
BlockMove( &fEntry->fName[j], &suffix[1], suffix[0] );
if( fpb.ioFlFndrInfo.fdCreator == RamSignature
|| EqualString(suffix, "\p.ram", FALSE, TRUE) )
{
*nameP = NewPtr( fEntry->fName[0] + 1 );
BlockMove( fEntry->fName, *nameP, fEntry->fName[0]+1 );
break;
}
}
}
if( *nameP ) { /* have a control file */
fEntryIndex = (char *)fEntry - (char *)applParmP;
fEntryLength = (sizeof(FEntry) + fEntry->fName[0]) & ~0x1;
Clear( pb );
pb.ioVRefNum = fEntry->vRefNum;
PBSetVol( &pb, FALSE );
if( (resRefNum = OpenResFile(*nameP)) < 0 ) /* ensure a resource fork */
CreateResFile( *nameP );
ramH = GetResource( 'RAMD', 256 ); /* ensure a size resource */
if( HomeResFile(ramH) != resRefNum ) {
if( !HandToHand(&ramH) ) {
AddResource( ramH, 'RAMD', 256, "\p" );
UpdateResFile( resRefNum );
}
}
ramH = GetResource( 'RAMD', 257 ); /* ensure a dir size resource */
if( HomeResFile(ramH) != resRefNum ) {
if( !HandToHand(&ramH) ) {
AddResource( ramH, 'RAMD', 257, "\p" );
UpdateResFile( resRefNum );
}
}
if( fpb.ioFlFndrInfo.fdCreator != RamSignature ) {
fpb.ioFlFndrInfo.fdCreator = RamSignature;
PBSetFInfo( &fpb, FALSE );
}
}
HUnlock( AppParmHandle );
}
}
/* // */
/* Remove the control file from the appl parms -- remove it entirely, don't
just zero its type -- and point all remaining files to the RAM disk, as we
expect they were copied there and the volume they were on has just been
ejected. This is a separate routine from GetCtrlFile() because that is
called once in each pass. */
ZapControlFile( ramDrvNum )
short ramDrvNum;
{
ApplParms *applParmP;
FEntry *fEntry;
short i;
if( AppParmHandle && fEntryLength ) { /* Remove command file. */
Munger( AppParmHandle,
fEntryIndex,
NULL,
fEntryLength,
"",
0 );
--(*(ApplParms **)AppParmHandle)->count;
}
applParmP = *(ApplParms **)AppParmHandle;
for( fEntry = (FEntry *)&applParmP->fList, i = 1; /* set volume on parm files */
i <= applParmP->count;
fEntry = (FEntry *)( (char *)fEntry + ((sizeof(FEntry) + fEntry->fName[0]) & ~0x1) ), ++i )
{
fEntry->vRefNum = ramDrvNum; /* claim the file is on the RAM disk */
}
}
/* // */
/* Reserve memory for the RAM disk. The top of useable memory is available
in BufPtr, which we save and then set lower to reserve memory. BufPtr is
observed by InitApplZone(). */
InitRamDisk( heapSize, ramStart, dirSize ) /* Called also by GetNewSize(). */
long heapSize; /* --> */
Ptr ramStart; /* --> */
long dirSize; /* --> */
{
if( dirSize < 1 || dirSize > 10 )
dirSize = 1;
applInfo.signature = RamSignature;
applInfo.oldBufPtr = ramInfo.oldBufPtr = BufPtr; /* The driver looks here. */
applInfo.initCmd = 'BD';
applInfo.initVal = dirSize;
if( (applInfo.oldBufPtr - ramStart) < MinDisk ) {
if( ((applInfo.oldBufPtr - ramStart) + (heapSize - MinHeap)) < MinDisk ) {
Alert( (MemTop == ThinMemTop) ? (short)alrtThinNoRoom : alrtFatNoRoom, NULL );
ExitToShell();
}
else { /* Can make it big enough to use. */
Alert( alrtSizeChange, NULL );
MakeCtlW( MinDisk );
GetNewSize();
}
}
BufPtr = ramInfo.ramDisk = ramStart; /* Reserves RAM disk memory. */
}
/* Create a RAM disk in the reserved memory. */
short MakeRamDisk()
{
ioParam pb;
Clear( pb );
pb.ioNamePtr = (StringPtr)RamName; /* The driver is in our file. */
pb.ioPermssn = 3; /* Read and Write. */
if( PBOpen( &pb, FALSE ) ) {
error("\pcan't open RAM disk driver, ioResult=^2", (long)pb.ioResult);
ExitToShell();
}
DetachResource( GetNamedResource('DRVR', pb.ioNamePtr) ); /* Keep in memory even after we quit. */
return( pb.ioRefNum );
}
/* // */
/* Find an unused drive number. Search the drive queue and find which
drive numbers are already in use; then choose the smallest one beyond the
Sony drives (>2).
The drive queue doesn't use a standard OS queue. For some awful reason,
a long word _before_ the link field contains flags, but the link still
points to the next link field. Sigh. */
/* Size must be a power of 2 */
#define InUseSize 64
short UnusedDrive()
{
char inUse[InUseSize];
short i;
DrvQEl *dqp;
/* Mark table entries for drive numbers in use. */
aClear( inUse, InUseSize );
for( dqp = (DrvQElPtr)DrvQHdr.qHead; dqp; dqp = (DrvQElPtr)dqp->qLink ) {
if( dqp->dQDrive > 0 && dqp->dQDrive < InUseSize ) /* array bounds check */
inUse[ dqp->dQDrive ] = TRUE;
}
/* Search table for an unused drive, not a Sony drive. */
for( i = 3; i < InUseSize; ++i ) {
if( ! inUse[i] )
return( i );
}
error("\pcan't find an unused drive number");
return( InUseSize );
}
/* // */
/* Add a new drive and mount the RAM disk in it. The drive is flagged as
not write protected and not doing ejects.*/
ChgDrvQ( ramRefNum, ramDrvNum, size )
short ramRefNum; /* --> */
short ramDrvNum; /* --> */
long size; /* --> */
{
DrvQElPtr dqp;
ioParam vpb;
long *flagsPtr;
dqp = (DrvQElPtr)( NewPtrSysClr(sizeof(DrvQEl) + 4) + 4 ); /* DrvQEl with flags at front */
AddDrive( ramRefNum, ramDrvNum, dqp );
flagsPtr = (long *)dqp - 1;
*flagsPtr = 0x00080000L; /* Not write protected, can't eject. */
dqp->dQDrvSize = size / 512; /* fill in drive size for DI pkg */
ramInfo.drvQEntry = (QElemPtr)dqp;
Clear( vpb );
vpb.ioVRefNum = ramDrvNum; /* Drive to mount volume in. */
if( PBMountVol(&vpb) )
error("\pcan't mount the RAM disk, ioResult=^2", (long)vpb.ioResult);
}
/* This probably wouldn't be necessary if Apple documented the File
Manager better. If the boot disk is write-protected, the RAM disk is
also! It doesn't matter that the new drive says that it isn't protected.
Here we clear that flag. */
FixVolInfo( ramDrvNum )
short ramDrvNum; /* --> */
{
QElem *vcbp;
vcbp = VCBQHdr.qHead;
while( TRUE ) {
if( *(short *)&vcbp->qData[72-6] == ramDrvNum ) { /* Is volume in our drive? */
*(short *)&vcbp->qData[18-6] &= ~0x0080; /* un-write protect it */
break;
}
if( ! (vcbp = vcbp->qLink) )
error("\pcan't find RAM disk to un-write protect it");
}
}
/* // */
/* Launch the finder on the RAM disk. The method was cribbed from Apple's
(pre-HFS) Finder. */
LaunchRamDisk( ramDrvNum, exitAppl )
short ramDrvNum; /* --> */
char *exitAppl; /* --> */
{
volumeParam pb;
QElem *vcbp;
Clear( pb ); /* Flush the RAM disk. */
pb.ioVRefNum = ramDrvNum;
PBFlshVol( &pb, FALSE );
pb.ioVRefNum = OurDriveNum();
if( pb.ioVRefNum == 1 || pb.ioVRefNum == 2 ) { /* Mac SE/II: may not refer to sony drives */
PBEject( &pb ); /* Eject the disk. We assume that this was the */
PBUnmountVol( &pb ); /* only mounted disk besides the RAM disk. */
/* System 4.2: disk won't unmount because our app is still open. */
}
/* // */
/* Set the default volume to the RAM disk and launch _its_ Finder. Key
parts of this code were cribbed from the Finder. */
pb.ioVRefNum = ramDrvNum;
PBSetVol( &pb, FALSE );
DetachResource( GetResource('CODE', 2) ); /* Us, so we don't go away when the */
CloseResFile( 0 ); /* old system file is closed. */
ResErrProc = 0; /* Finder magic. */
InitResources(); /* new system file */
InitFonts();
BootDrive = ramDrvNum; /* Finder magic. */
PBSetVol( &pb, FALSE ); /* Finder magic. */
Launch( 0, exitAppl );
}
/* Start us over again. This re-initializes the application heap, which is
when BufPtr is observed so RAM disk memory is reserved. */
ReStartUs()
{
Launch( 0, CurApName ); /* We shall return. */
}
/* // */
/* Remove any RAM disk. Each of the actions below is (almost always) safe,
even if it doesn't work in some circumstances. If an error occurs, there
isn't much to be done about it, so most are ignored. We are paranoid about
other disk drivers, etc. */
NoRamDisk()
/* extern RamInfo ramInfo; */ /* --> */
{
register DrvQElPtr dqp;
ioParam pb;
register short sigWord;
SetCursor( *GetCursor(watchCursor) );
if( BufPtr == ramInfo.ramDisk )
BufPtr = ramInfo.oldBufPtr; /* Restore mem top so all memory is available. */
if( ramInfo.drvQEntry ) {
dqp = (DrvQElPtr)ramInfo.drvQEntry;
/* Remove everything we can find. */
Clear( pb ); /* Get rid of the disk, */
pb.ioVRefNum = dqp->dQDrive;
if( PBUnmountVol(&pb) )
error( "\pNoRamDisk() can't unmount RAM disk, ioResult=^2", (long)pb.ioResult );
Dequeue( dqp, &DrvQHdr ); /* the drive, */
DisposPtr( (char *)dqp - 4 );
pb.ioRefNum = ~ramID; /* and the driver. */
PBClose( &pb, FALSE );
}
/* Tell the RAM disk driver (next time) that the disk is not set up. */
sigWord = *(short *)&ramInfo.ramDisk[SigWord];
if( ramInfo.ramDisk && (sigWord == 0xd2d7 || sigWord == 0x4244) )
*(short *)&ramInfo.ramDisk[SigWord] = 0xFFFF; /* Tells RAM disk driver. */
}
/* // */
error( err, m1, m2, str )
char *err;
long m1, m2; /* message data that may have been sent */
char *str;
{
char s1[32], s2[32];
if( TraceTrap < ROMBase )
DebugStr( err );
NumToString( m1, s1 );
NumToString( m2, s2 );
ParamText( err, str, s1, s2 );
if( Alert(128, NULL) == 1 ) {
NoRamDisk();
ExitToShell();
}
}
/* // */
/* Variant form of NewPtr. */
short NewPtrSysClrCode[5] = { 0x202F, 0x0004, /* move.l 4(sp),d0 */
0xA71E, /* _NewPtr,SYS,CLR */
0x2008, /* move.l a0,d0 */
0x4E75 }; /* rts */
/* Clear a block of memory. */
aClear( p, len )
register Ptr p;
register short len;
{
while( len-- )
*p++ = 0;
}